package config

import (
	"bufio"
	"errors"
	"io"
	"io/ioutil"
	"os"
	"os/user"
	"path"
	"regexp"
	"strings"
	"time"
)

var SSHInfo = &SSHConfig{}

type SSHConfig struct {
	Inventory            string
	Host                 string
	Hosts                []string
	Port                 int
	User                 string
	Password             string
	Key                  string
	KeyPassphrase        string
	BastionHost          string
	BastionPort          int
	BastionUser          string
	BastionPassword      string
	BastionKey           string
	BastionKeyPassphrase string
	Fork                 int
	ConnectTimeout       time.Duration
	PrintFields          []string
	PrintStatus          []string
	Args                 []string
}

func (s *SSHConfig) Parse() error {
	// 获取主机地址列表
	s.Hosts = make([]string, 0, 10)
	if s.Host != "" {
		s.Hosts = append(s.Hosts, strings.Split(s.Host, ",")...)
	}
	if s.Inventory != "" {
		list, err := readIPList(s.Inventory)
		if err != nil {
			return err
		}
		s.Hosts = append(s.Hosts, list...)
	}
	if len(s.Hosts) == 0 {
		return errors.New("not found any remote host address")
	}
	// 获取运行用户
	if s.User == "" {
		currenUser, err := user.Current()
		if err != nil {
			return err
		}
		s.User = currenUser.Username
	}
	// 读取ssh key
	if s.Password == "" {
		if s.Key == "~/.ssh/id_rsa" {
			currenUser, err := user.Current()
			if err != nil {
				return err
			}
			s.Key = path.Join(currenUser.HomeDir, ".ssh/id_rsa")
		}
		key, err := readSSHKey(s.Key)
		if err != nil {
			return err
		}
		s.Key = key
	} else {
		s.Key = ""
	}

	// 如果不存在跳板机
	if s.BastionHost == "" {
		return nil
	}
	if s.BastionUser == "" {
		s.BastionUser = s.User
	}
	if s.BastionPassword == "" {
		if s.BastionKey == "~/.ssh/id_rsa" {
			currenUser, err := user.Current()
			if err != nil {
				return err
			}
			s.BastionKey = path.Join(currenUser.HomeDir, ".ssh/id_rsa")
		}
		key, err := readSSHKey(s.BastionKey)
		if err != nil {
			return err
		}
		s.BastionKey = key
	} else {
		s.BastionKey = ""
	}
	return nil

}

func readIPList(file string) ([]string, error) {
	var res = make([]string, 0, 10)
	fd, err := os.Open(file)
	if err != nil {
		return nil, err
	}
	defer fd.Close()
	reader := bufio.NewReaderSize(fd, 128)
	for {
		line, _, err := reader.ReadLine()
		if err == io.EOF {
			break
		} else if err != nil {
			return nil, err
		}
		if len(line) == 0 {
			continue
		}
		match, _ := regexp.Match("^([0-9]|[a-zA-Z])+", line)
		if match {
			res = append(res, string(line))
		}
	}
	return res, err
}

func readSSHKey(file string) (string, error) {
	readFile, err := ioutil.ReadFile(file)
	if err != nil {
		return "", err
	}
	return string(readFile), nil
}
